package net.goutalk.glcs.module.authority.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import net.goutalk.glcs.common.constant.GlobalConstant;
import net.goutalk.glcs.common.enums.DataAuthMethodEnum;
import net.goutalk.glcs.common.enums.YesOrNoEnum;
import net.goutalk.glcs.common.utils.RedisUtil;
import net.goutalk.glcs.common.utils.VoToColumnUtil;
import net.goutalk.glcs.module.authority.dto.AddDataAuthDto;
import net.goutalk.glcs.module.authority.dto.UpdateDataAuthDto;
import net.goutalk.glcs.module.authority.entity.DataAuth;
import net.goutalk.glcs.module.authority.entity.DataAuthConfig;
import net.goutalk.glcs.module.authority.entity.DataAuthRelation;
import net.goutalk.glcs.module.authority.mapper.DataAuthMapper;
import net.goutalk.glcs.module.authority.service.IDataAuthConfigService;
import net.goutalk.glcs.module.authority.service.IDataAuthRelationService;
import net.goutalk.glcs.module.authority.service.IDataAuthService;
import net.goutalk.glcs.module.authority.vo.AuthObjectVo;
import net.goutalk.glcs.module.organization.entity.Role;
import net.goutalk.glcs.module.organization.entity.User;
import net.goutalk.glcs.module.organization.service.IRoleService;
import net.goutalk.glcs.module.organization.service.IUserService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 数据权限表 服务实现类
 * </p>
 *
 * @author tanyujie
 * @since 2023-02-27
 */
@Service
@AllArgsConstructor
public class DataAuthServiceImpl extends MPJBaseServiceImpl<DataAuthMapper, DataAuth> implements IDataAuthService {
    private final IDataAuthConfigService authConfigService;

    private final IDataAuthRelationService authRelationService;

    private final IRoleService roleService;

    private final IUserService userService;

    private RedisUtil redisUtil;

    @Override
    public Boolean add(AddDataAuthDto dto) {
        DataAuth dataAuth = BeanUtil.toBean(dto, DataAuth.class);
        this.save(dataAuth);
        redisUtil.set(GlobalConstant.DATA_AUTH_CACHE_KEY, this.list());
        //如果是自定义
        if (dataAuth.getAuthMethod() == DataAuthMethodEnum.CUSTOM.getCode()) {
            List<DataAuthConfig> authConfigs = BeanUtil.copyToList(dto.getAuthConfigList(), DataAuthConfig.class);
            for (DataAuthConfig authConfig : authConfigs) {
                authConfig.setDataAuthId(dataAuth.getId());
            }
            authConfigService.saveBatch(authConfigs);
            redisUtil.set(GlobalConstant.DATA_AUTH_CONFIG_CACHE_KEY, authConfigService.list());
        }

        List<DataAuthRelation> authRelations = new ArrayList<>();
        for (Long objId : dto.getObjectIdList()) {
            DataAuthRelation relation = new DataAuthRelation();
            relation.setDataAuthId(dataAuth.getId());
            relation.setObjectId(objId);
            authRelations.add(relation);
        }
        authRelationService.saveBatch(authRelations);
        redisUtil.set(GlobalConstant.DATA_AUTH_RELATION_CACHE_KEY, authRelationService.list());
        return true;
    }

    @Override
    public Boolean edit(UpdateDataAuthDto dto) {
        DataAuth dataAuth = BeanUtil.toBean(dto, DataAuth.class);

        //如果是自定义
        if (dataAuth.getAuthMethod() == DataAuthMethodEnum.CUSTOM.getCode()) {
            List<DataAuthConfig> authConfigs = BeanUtil.copyToList(dto.getAuthConfigList(), DataAuthConfig.class);
            for (DataAuthConfig authConfig : authConfigs) {
                authConfig.setDataAuthId(dataAuth.getId());
            }
            //移除原有的数据
            authConfigService.remove(Wrappers.lambdaQuery(DataAuthConfig.class).eq(DataAuthConfig::getDataAuthId,dto.getId()));
            authConfigService.saveBatch(authConfigs);
            redisUtil.set(GlobalConstant.DATA_AUTH_CONFIG_CACHE_KEY, authConfigService.list());
        }

        List<DataAuthRelation> authRelations = new ArrayList<>();
        for (Long objId : dto.getObjectIdList()) {
            DataAuthRelation relation = new DataAuthRelation();
            relation.setDataAuthId(dataAuth.getId());
            relation.setObjectId(objId);
            authRelations.add(relation);
        }
        //移除原有的数据
        authRelationService.remove(Wrappers.lambdaQuery(DataAuthRelation.class).eq(DataAuthRelation::getDataAuthId,dto.getId()));
        authRelationService.saveBatch(authRelations);
        redisUtil.set(GlobalConstant.DATA_AUTH_RELATION_CACHE_KEY, authRelationService.list());

        boolean isSuccess = this.updateById(dataAuth);
        redisUtil.set(GlobalConstant.DATA_AUTH_CACHE_KEY, this.list());
        return true;
    }

    @Override
    public List<AuthObjectVo> getAuthObjectsInfo(Long id) {
        DataAuth data = this.getById(id);
        List<Object> objectIdList = authRelationService.listObjs(Wrappers.<DataAuthRelation>query().lambda()
                .select(DataAuthRelation::getObjectId)
                .eq(DataAuthRelation::getDataAuthId, id));
        List<AuthObjectVo> result = new ArrayList<>();
        if (data.getAuthType() == YesOrNoEnum.NO.getCode()) {
            List<Role> roleList = roleService.list(Wrappers.<Role>query().lambda()
                    .select(Role.class, x -> VoToColumnUtil.fieldsToColumns(AuthObjectVo.class).contains(x.getProperty()))
                    .in(Role::getId, objectIdList));
            result = BeanUtil.copyToList(roleList, AuthObjectVo.class);
            return result;
        } else if (data.getAuthType() == YesOrNoEnum.YES.getCode()) {
            List<User> userList = userService.list(Wrappers.<User>query().lambda()
                    .select(User.class, x -> VoToColumnUtil.fieldsToColumns(AuthObjectVo.class).contains(x.getProperty()))
                    .in(User::getId, objectIdList));
            result = BeanUtil.copyToList(userList, AuthObjectVo.class);
            return result;
        }
        return result;
    }

}
